﻿#include <Windows.h>
#include <iostream>
#include <string>
#include <signal.h>
#include <cstdlib>
#include <DbgHelp.h>

typedef BOOL(WINAPI* MiniDumpWriteDumpFunc)(
	HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
	PMINIDUMP_EXCEPTION_INFORMATION,
	PMINIDUMP_USER_STREAM_INFORMATION,
	PMINIDUMP_CALLBACK_INFORMATION
	);

bool GenerateMiniDump(EXCEPTION_POINTERS* pep = nullptr, const std::wstring& dumpPath = L"CrashDump.dmp")
{
	HMODULE hDbgHelp = LoadLibrary(L"DbgHelp.dll");
	if (!hDbgHelp)
	{
		std::cerr << "DbgHelp.dll 加载失败！错误代码: " << GetLastError() << std::endl;
		return false;
	}

	auto pMiniDumpWriteDump = (MiniDumpWriteDumpFunc)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
	if (!pMiniDumpWriteDump)
	{
		std::cerr << "找不到 MiniDumpWriteDump！错误代码: " << GetLastError() << std::endl;
		FreeLibrary(hDbgHelp);
		return false;
	}

	HANDLE hFile = CreateFileW(dumpPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		std::cerr << "无法创建 Dump 文件！错误代码: " << GetLastError() << std::endl;
		FreeLibrary(hDbgHelp);
		return false;
	}

	MINIDUMP_EXCEPTION_INFORMATION mdei;
	mdei.ThreadId = GetCurrentThreadId();
	mdei.ExceptionPointers = pep;
	mdei.ClientPointers = FALSE;

	BOOL success = pMiniDumpWriteDump(
		GetCurrentProcess(),
		GetCurrentProcessId(),
		hFile,
		MiniDumpWithFullMemory,
		pep ? &mdei : nullptr,
		nullptr,
		nullptr
	);

	CloseHandle(hFile);
	FreeLibrary(hDbgHelp);

	if (!success)
	{
		std::cerr << "MiniDumpWriteDump 失败！错误代码: " << GetLastError() << std::endl;
		return false;
	}

	std::wcout << L"Dump 文件已生成: " << dumpPath << std::endl;
	return true;
}

LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* pep)
{
	GenerateMiniDump(pep);
	return EXCEPTION_EXECUTE_HANDLER;
}

void LockExceptionFilter()
{
	SetUnhandledExceptionFilter(ExceptionHandler);
	_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
}

int main()
{
	LockExceptionFilter();
	_set_purecall_handler([] { GenerateMiniDump(); abort(); });
	signal(SIGSEGV, [](int) { GenerateMiniDump(); exit(1); });

	// 测试崩溃
	int* p = nullptr;
	*p = 42;  // 触发访问冲突

	return 0;
}
